package model

import (
	"fmt"
	"gowork/trainingManagementSystem/utils"
	"strconv"
	"strings"
	"sync"
	"time"
)

type Questionnaire struct {
	Id int64 `xorm:"pk autoincr"`
	Name string
	QualifiedScore int
	TestPaperDescription string
	SingleChoiceQuestionList []*SingleChoiceQuestions `xorm:"-"`
	MultipleChoiceQuestionList []*MultipleChoiceQuestion `xorm:"-"`
	JudgmentQuestionList []*JudgmentQuestions `xorm:"-"`
	ShortAnswerQuestionList []*ShortAnswerQuestions `xorm:"-"`
	UserId int64 `xorm:"-"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

type SingleChoiceQuestions struct {
	Id int64 `xorm:"pk autoincr"`
	Type int
	QuestionnaireId int64
	TestScore int
	TitleStemConten string
	OptionList []*SingleOrMultipleOptions `xorm:"-"`
	RightKey string
	Right bool `xorm:"-"`
	AnswersSubmittedByStudents string `xorm:"-"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

type MultipleChoiceQuestion struct {
	Id int64 `xorm:"pk autoincr"`
	Type int
	QuestionnaireId int64
	TestScore int
	TitleStemConten string
	OptionList []*SingleOrMultipleOptions `xorm:"-"`
	RightKey string
	Right bool `xorm:"-"`
	AnswersSubmittedByStudents string `xorm:"-"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

type SingleOrMultipleOptions struct {
	Id int64 `xorm:"pk autoincr"`
	SingleOrMultipleQuestionId int64
	Name string
	Selected bool `xorm:"-"`
	OptionsContent string
	CreatedAt time.Time
	UpdatedAt time.Time
}

type JudgmentQuestions struct {
	Id int64 `xorm:"pk autoincr"`
	Type int
	QuestionnaireId int64
	TestScore int
	TitleStemConten string
	RightKey int
	Right bool `xorm:"-"`
	AnswersSubmittedByStudents int `xorm:"-"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ShortAnswerQuestions struct {
	Id int64 `xorm:"pk autoincr"`
	Type int
	QuestionnaireId int64
	TestScore int
	TitleStemConten string
	RightKey string
	Right bool `xorm:"-"`
	AnswersSubmittedByStudents string `xorm:"-"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

type AnswerSheet struct {
	Id int64 `xorm:"pk autoincr"`
	UserId int64
	QuestionnaireId int64
	SubjectId int64
	Answer string
	Correct bool
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ExaminationRecord struct {
	Id int64 `xorm:"pk autoincr"`
	UserId int64
	QuestionnaireId int64
	StudentScore int
	CreatedAt time.Time
	UpdatedAt time.Time
}

func (q *Questionnaire)InsertQuestionnaire(qv *Questionnaire)(map[string]interface{}, error){

	w := new(utils.Worker)

	qv.Id = w.GetId()
	qv.CreatedAt = time.Now()
	qv.UpdatedAt = time.Now()
	x.Insert(qv)

	for _ ,scqv := range qv.SingleChoiceQuestionList{
		scqv.Id = w.GetId()
		scqv.QuestionnaireId = qv.Id
		scqv.CreatedAt = time.Now()
		scqv.UpdatedAt = time.Now()
		x.Insert(scqv)

		for _, o := range scqv.OptionList{
			o.Id = w.GetId()
			o.SingleOrMultipleQuestionId = scqv.Id
			o.CreatedAt = time.Now()
			o.UpdatedAt = time.Now()
			x.Insert(o)
		}
	}

	for _ ,mcqv := range qv.MultipleChoiceQuestionList{
		mcqv.Id = w.GetId()
		mcqv.QuestionnaireId = qv.Id
		mcqv.CreatedAt = time.Now()
		mcqv.UpdatedAt = time.Now()
		x.Insert(mcqv)

		for _, o := range mcqv.OptionList{
			o.Id = w.GetId()
			o.SingleOrMultipleQuestionId = mcqv.Id
			o.CreatedAt = time.Now()
			o.UpdatedAt = time.Now()
			x.Insert(o)
		}
	}

	for _, jqv := range qv.JudgmentQuestionList{
		jqv.Id = w.GetId()
		jqv.QuestionnaireId = qv.Id
		jqv.CreatedAt = time.Now()
		jqv.UpdatedAt = time.Now()
		x.Insert(jqv)
	}

	for _, saqv := range qv.ShortAnswerQuestionList{
		saqv.Id = w.GetId()
		saqv.QuestionnaireId = qv.Id
		saqv.CreatedAt = time.Now()
		saqv.UpdatedAt = time.Now()
		x.Insert(saqv)
	}

	return map[string]interface{}{"message":"成功","code":200}, nil
}

func (q *Questionnaire)InsertQuestionnaireAsync(qv *Questionnaire)(map[string]interface{}, error){

	w := new(utils.Worker)

	qv.Id = w.GetId()
	qv.CreatedAt = time.Now()
	qv.UpdatedAt = time.Now()
	x.Insert(qv)

	var wg sync.WaitGroup
	wg.Add(4)
	
	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, scqv := range qv.SingleChoiceQuestionList {
			scqv.Id = w.GetId()
			scqv.QuestionnaireId = qv.Id
			scqv.CreatedAt = time.Now()
			scqv.UpdatedAt = time.Now()
			x.Insert(scqv)

			for _, o := range scqv.OptionList {
				o.Id = w.GetId()
				o.SingleOrMultipleQuestionId = scqv.Id
				o.CreatedAt = time.Now()
				o.UpdatedAt = time.Now()
				x.Insert(o)
			}
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, mcqv := range qv.MultipleChoiceQuestionList {
			mcqv.Id = w.GetId()
			mcqv.QuestionnaireId = qv.Id
			mcqv.CreatedAt = time.Now()
			mcqv.UpdatedAt = time.Now()
			x.Insert(mcqv)

			for _, o := range mcqv.OptionList {
				o.Id = w.GetId()
				o.SingleOrMultipleQuestionId = mcqv.Id
				o.CreatedAt = time.Now()
				o.UpdatedAt = time.Now()
				x.Insert(o)
			}
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, jqv := range qv.JudgmentQuestionList {
			jqv.Id = w.GetId()
			jqv.QuestionnaireId = qv.Id
			jqv.CreatedAt = time.Now()
			jqv.UpdatedAt = time.Now()
			x.Insert(jqv)
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, saqv := range qv.ShortAnswerQuestionList {
			saqv.Id = w.GetId()
			saqv.QuestionnaireId = qv.Id
			saqv.CreatedAt = time.Now()
			saqv.UpdatedAt = time.Now()
			x.Insert(saqv)
		}
		
		wg.Done()
	}()

	wg.Wait()
	
	return map[string]interface{}{"message":"成功","code":200}, nil
}

func (q *Questionnaire)QueryQuestionnaire(qId int64)(*Questionnaire, error) {
	var questionnaire Questionnaire

	x.Id(qId).Get(&questionnaire)
	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.SingleChoiceQuestionList)
	for _ ,scqv := range questionnaire.SingleChoiceQuestionList{
		x.Where("single_or_multiple_question_id = ?",scqv.Id).Find(&scqv.OptionList)
	}

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.MultipleChoiceQuestionList)
	for _ ,mcqv := range questionnaire.MultipleChoiceQuestionList{
		x.Where("single_or_multiple_question_id = ?",mcqv.Id).Find(&mcqv.OptionList)
	}

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.JudgmentQuestionList)

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.ShortAnswerQuestionList)

	return &questionnaire, nil
}

func (q *Questionnaire)SubmitTheAnswerSheet(qv *Questionnaire)(int, error){

	w := new(utils.Worker)

	var score int

	for _, scqv := range qv.SingleChoiceQuestionList{

		var as = AnswerSheet{
			Id:              w.GetId(),
			UserId:          qv.UserId,
			QuestionnaireId: qv.Id,
			SubjectId:       scqv.Id,
			Answer:        	 scqv.AnswersSubmittedByStudents,
			CreatedAt:       time.Now(),
			UpdatedAt:       time.Now(),
		}

		if scqv.RightKey == scqv.AnswersSubmittedByStudents{
			score += scqv.TestScore
			as.Correct = true
		}
		x.Insert(&as)
	}

	for _, mcqv := range qv.MultipleChoiceQuestionList{

		var as = AnswerSheet{
			Id:              w.GetId(),
			UserId:          qv.UserId,
			QuestionnaireId: qv.Id,
			SubjectId:       mcqv.Id,
			Answer:          mcqv.AnswersSubmittedByStudents,
			CreatedAt:       time.Now(),
			UpdatedAt:       time.Now(),
		}

		answerList := strings.Split(mcqv.RightKey, ",")
		fmt.Println("正确答案：", answerList, "  ", len(answerList))
		submittedList := strings.Split(mcqv.AnswersSubmittedByStudents, ",")
		fmt.Println("提交答案：", submittedList, "  ", len(submittedList))

		if len(submittedList) == len(answerList) {
			var count int = 0
			for _, submitted := range submittedList{
				for _, answer := range answerList{
					if submitted == answer{
						count += 1
					}
				}
			}
			if count == len(answerList){
				score += mcqv.TestScore
				as.Correct = true
			}
		}else if len(answerList) > len(submittedList){
			var count int = 0
			for _, submitted := range submittedList{
				for _, answer := range answerList{
					if submitted == answer{
						count += 1
					}
				}
			}
			if count == len(submittedList){
				score += mcqv.TestScore / 2
				as.Correct = true
			}
			fmt.Println("回答正确的答案数：", count)
		}
		x.Insert(&as)
	}

	for _, jqv := range qv.JudgmentQuestionList{

		answer := strconv.Itoa(jqv.AnswersSubmittedByStudents)
		var as = AnswerSheet{
			Id:              w.GetId(),
			UserId:          qv.UserId,
			QuestionnaireId: qv.Id,
			SubjectId:       jqv.Id,
			Answer:        	 answer,
			CreatedAt:       time.Now(),
			UpdatedAt:       time.Now(),
		}

		if jqv.RightKey == jqv.AnswersSubmittedByStudents{
			score += jqv.TestScore
			as.Correct = true
		}
		x.Insert(&as)
	}

	for _, saqv := range qv.ShortAnswerQuestionList{

		var as = AnswerSheet{
			Id:              w.GetId(),
			UserId:          qv.UserId,
			QuestionnaireId: qv.Id,
			SubjectId:       saqv.Id,
			Answer:        	 saqv.AnswersSubmittedByStudents,
			CreatedAt:       time.Now(),
			UpdatedAt:       time.Now(),
		}
		x.Insert(&as)
	}

	var er = ExaminationRecord{
		Id:              w.GetId(),
		UserId:          qv.UserId,
		QuestionnaireId: qv.Id,
		StudentScore:    score,
		CreatedAt:       time.Now(),
		UpdatedAt:       time.Now(),
	}
	x.Insert(&er)

	return score, nil
}

func (q *Questionnaire)SubmitTheAnswerSheetAsync(qv *Questionnaire)(int, error){

	w := new(utils.Worker)

	var score int

	var wg sync.WaitGroup
	wg.Add(4)
	
	var lock sync.Mutex
	
	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, scqv := range qv.SingleChoiceQuestionList {

			var as = AnswerSheet{
				Id:              w.GetId(),
				UserId:          qv.UserId,
				QuestionnaireId: qv.Id,
				SubjectId:       scqv.Id,
				Answer:          scqv.AnswersSubmittedByStudents,
				CreatedAt:       time.Now(),
				UpdatedAt:       time.Now(),
			}

			if scqv.RightKey == scqv.AnswersSubmittedByStudents {
				
				lock.Lock()
				score += scqv.TestScore
				lock.Unlock()
				
				as.Correct = true
			}
			x.Insert(&as)
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, mcqv := range qv.MultipleChoiceQuestionList {

			var as = AnswerSheet{
				Id:              w.GetId(),
				UserId:          qv.UserId,
				QuestionnaireId: qv.Id,
				SubjectId:       mcqv.Id,
				Answer:          mcqv.AnswersSubmittedByStudents,
				CreatedAt:       time.Now(),
				UpdatedAt:       time.Now(),
			}

			answerList := strings.Split(mcqv.RightKey, ",")
			fmt.Println("正确答案：", answerList, "  ", len(answerList))
			submittedList := strings.Split(mcqv.AnswersSubmittedByStudents, ",")
			fmt.Println("提交答案：", submittedList, "  ", len(submittedList))

			if len(submittedList) == len(answerList) {
				var count int = 0
				for _, submitted := range submittedList {
					for _, answer := range answerList {
						if submitted == answer {
							count += 1
						}
					}
				}
				if count == len(answerList) {
					
					lock.Lock()
					score += mcqv.TestScore
					lock.Unlock()
					
					as.Correct = true
				}
			} else if len(answerList) > len(submittedList) {
				var count int = 0
				for _, submitted := range submittedList {
					for _, answer := range answerList {
						if submitted == answer {
							count += 1
						}
					}
				}
				if count == len(submittedList) {
					
					lock.Lock()
					score += mcqv.TestScore / 2
					lock.Unlock()
					
					as.Correct = true
				}
				fmt.Println("回答正确的答案数：", count)
			}
			x.Insert(&as)
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, jqv := range qv.JudgmentQuestionList {

			answer := strconv.Itoa(jqv.AnswersSubmittedByStudents)
			var as = AnswerSheet{
				Id:              w.GetId(),
				UserId:          qv.UserId,
				QuestionnaireId: qv.Id,
				SubjectId:       jqv.Id,
				Answer:          answer,
				CreatedAt:       time.Now(),
				UpdatedAt:       time.Now(),
			}

			if jqv.RightKey == jqv.AnswersSubmittedByStudents {
				
				lock.Lock()
				score += jqv.TestScore
				lock.Unlock()
				
				as.Correct = true
			}
			x.Insert(&as)
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		for _, saqv := range qv.ShortAnswerQuestionList {

			var as = AnswerSheet{
				Id:              w.GetId(),
				UserId:          qv.UserId,
				QuestionnaireId: qv.Id,
				SubjectId:       saqv.Id,
				Answer:          saqv.AnswersSubmittedByStudents,
				CreatedAt:       time.Now(),
				UpdatedAt:       time.Now(),
			}
			x.Insert(&as)
		}
		
		wg.Done()
	}()

	var er = ExaminationRecord{
		Id:              w.GetId(),
		UserId:          qv.UserId,
		QuestionnaireId: qv.Id,
		StudentScore:    score,
		CreatedAt:       time.Now(),
		UpdatedAt:       time.Now(),
	}
	x.Insert(&er)

	wg.Wait()
	
	return score, nil
}

func (q *Questionnaire)Marking(qId int64, uId int64)(*Questionnaire, error){

	var questionnaire Questionnaire
	x.Id(qId).Get(&questionnaire)

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.SingleChoiceQuestionList)
	for _ ,scqv := range questionnaire.SingleChoiceQuestionList{
		x.Where("single_or_multiple_question_id = ?",scqv.Id).Find(&scqv.OptionList)

		var as AnswerSheet
		x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", scqv.Id).Get(&as)

		for _, o := range scqv.OptionList{
			if o.Name == as.Answer {
				o.Selected = true
			}
		}
		scqv.AnswersSubmittedByStudents = as.Answer

		scqv.Right = as.Correct
	}

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.MultipleChoiceQuestionList)
	for _ ,mcqv := range questionnaire.MultipleChoiceQuestionList{
		x.Where("single_or_multiple_question_id = ?",mcqv.Id).Find(&mcqv.OptionList)

		var as AnswerSheet
		x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", mcqv.Id).Get(&as)

		answerList := strings.Split(as.Answer, ",")
		for _, aw := range answerList{
			for _, o := range mcqv.OptionList{
				if o.Name == aw {
					o.Selected = true
				}
			}
		}
		mcqv.AnswersSubmittedByStudents = as.Answer

		mcqv.Right = as.Correct
	}

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.JudgmentQuestionList)
	for _, jqv := range questionnaire.JudgmentQuestionList{
		var as AnswerSheet
		x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", jqv.Id).Get(&as)
		answer, err := strconv.Atoi(as.Answer)
		if err != nil{
			return nil ,err
		}
		jqv.AnswersSubmittedByStudents = answer

		jqv.Right = as.Correct
	}

	x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.ShortAnswerQuestionList)
	for _, saqv := range questionnaire.ShortAnswerQuestionList{
		var as AnswerSheet
		x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", saqv.Id).Get(&as)
		saqv.AnswersSubmittedByStudents = as.Answer

		saqv.Right = as.Correct
	}

	return &questionnaire, nil
}

func (q *Questionnaire)MarkingAsync(qId int64, uId int64)(*Questionnaire, error){

	var questionnaire Questionnaire
	x.Id(qId).Get(&questionnaire)

	var wg sync.WaitGroup
	wg.Add(4)
	
	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.SingleChoiceQuestionList)
		for _, scqv := range questionnaire.SingleChoiceQuestionList {
			x.Where("single_or_multiple_question_id = ?", scqv.Id).Find(&scqv.OptionList)

			var as AnswerSheet
			x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", scqv.Id).Get(&as)

			for _, o := range scqv.OptionList {
				if o.Name == as.Answer {
					o.Selected = true
				}
			}
			scqv.AnswersSubmittedByStudents = as.Answer

			scqv.Right = as.Correct
		}
		
		wg.Done()
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.MultipleChoiceQuestionList)
		for _, mcqv := range questionnaire.MultipleChoiceQuestionList {
			x.Where("single_or_multiple_question_id = ?", mcqv.Id).Find(&mcqv.OptionList)

			var as AnswerSheet
			x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", mcqv.Id).Get(&as)

			answerList := strings.Split(as.Answer, ",")
			for _, aw := range answerList {
				for _, o := range mcqv.OptionList {
					if o.Name == aw {
						o.Selected = true
					}
				}
			}
			mcqv.AnswersSubmittedByStudents = as.Answer

			mcqv.Right = as.Correct
		}
		
		wg.Done()
	}()

	go func() (interface{}, error){
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.JudgmentQuestionList)
		for _, jqv := range questionnaire.JudgmentQuestionList {
			var as AnswerSheet
			x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", jqv.Id).Get(&as)
			answer, err := strconv.Atoi(as.Answer)
			if err != nil {
				return nil, err
			}
			jqv.AnswersSubmittedByStudents = answer

			jqv.Right = as.Correct
		}
		
		wg.Done()

		return nil, nil
	}()

	go func() {
		defer func() {
			// 捕获异常 防止waitGroup阻塞
			if err := recover(); err != nil {
				wg.Done()
			}
		}()

		x.Where("questionnaire_id = ?", questionnaire.Id).Find(&questionnaire.ShortAnswerQuestionList)
		for _, saqv := range questionnaire.ShortAnswerQuestionList {
			var as AnswerSheet
			x.Where("user_id = ?", uId).And("questionnaire_id = ?", qId).And("subject_id = ?", saqv.Id).Get(&as)
			saqv.AnswersSubmittedByStudents = as.Answer

			saqv.Right = as.Correct
		}
		
		wg.Done()
	}()

	wg.Wait()
	
	return &questionnaire, nil
}























